feat(usage): real Claude subscription usage bars (5h + weekly) - #150
Merged
Conversation
DIodide
added a commit
that referenced
this pull request
Jun 22, 2026
fix(usage): harden subscription-usage fetch (review follow-ups to #150)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The AGENT USAGE panel showed only an estimated cost (the SDK's
total_cost_usd, e.g. "$6.40 today · $6.40 wk") for Claude Code credentials. For an OAuth/subscription credential the meaningful number is the real 5-hour + weekly limit consumption — what Claude Code's/usageshows — not a dollar estimate.Why it wasn't there already
The app already captures
_meta._claude/rateLimitfrom the ACP stream and renders one bar from it (AccountLimitsSection) — but driving a real agent showed that signal is empty (agent_usage meta_keys=[]). The current Claude Agent SDK / ACP doesn't surface subscription usage. The dedicatedGET /api/oauth/usageendpoint needs auser:profilescope the inference token lacks (403).What does work (verified against the real token): the
anthropic-ratelimit-unified-5h-*/-7d-*/-7d_sonnet-*headers ride on every/v1/messagesresponse — the exact source Claude Code's/usagereads.Change
usage.py):fetch_subscription_usage()makes the cheapest possible/v1/messagesping (max_tokens: 1) with the credential's OAuth token and parses the unified headers into a multi-window{ buckets: { five_hour, seven_day, seven_day_sonnet } }snapshot (utilization 0–1, reset timestamps). Best-effort — returnsNoneon any error rather than disrupting a turn.session_manager.py): at the turn boundary, when the SDK carries no rate-limit meta, fire a debounced (≤1/min per credential) background fetch that resolves the OAuth token, p ings, and persists the snapshot via the existingrecordRateLimit. OAuth-only (api-key creds have no subscription windows and are skipped). No schema change —lastRateLimitis alreadyv.any().usage-display.tsx):accountUsagesFromRateLimitnow parses the multi-windowbucketsshape into an ordered array (keeping the legacy flat single-window as a fallback), andAccountLimitsSectionrenders one ProgressBar per window — reusing the existing budget-bar UI verbatim.Verified live
Drove a real Claude Code agent (Daytona sandbox, real OAuth credential). The ping fired (
POST api.anthropic.com/v1/messages 200), the snapshot stored, and the panel rendered:Tests
None). Full suite green.Note on labels
Claude subscriptions don't have a literal "daily" limit — the short window is a 5-hour rolling session. The bars are labeled accordingly ("Current session" + "Current week") with live reset times, matching Claude Code's
/usage. The estimated cost line is kept below as supplementary detail.🤖 Generated with Claude Code